package com.ruoyi.exam.serive.impl;

import com.ruoyi.common.vo.PageResult;
import com.ruoyi.exam.domain.ExamUnreal;
import com.ruoyi.exam.mapper.ExamUnrealMapper;
import com.ruoyi.exam.serive.IExamUnrealService;
import com.ruoyi.exam.vo.ExamUnrealAnswer;
import com.ruoyi.exam.vo.ExamUnrealListVO;
import com.ruoyi.exam.vo.ExamUnrealQuestionData;
import com.ruoyi.questionBank.domain.Question;
import com.ruoyi.questionBank.domain.QuestionBank;
import com.ruoyi.questionBank.service.IQuestionBankService;
import com.ruoyi.questionBank.service.IQuestionService;
import com.ruoyi.questionBank.vo.QuestionListVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ExamUnrealServiceImpl implements IExamUnrealService {
    @Autowired
    private ExamUnrealMapper unrealMapper;
    @Autowired
    private IQuestionService questionService;
    @Autowired
    private IQuestionBankService bankService;

    /**
     * 是否版本落后题库
     * @param unreal
     * @param bank
     * @return
     */
    private void belowQuestionBankVersion(ExamUnreal unreal , QuestionBank bank){
        if(unreal == null){
            return;
        }
        long currVersion = unreal.getQuestionBankVersion();
        if(currVersion < bank.getQuEnable() || currVersion < bank.getQuDel() || currVersion < bank.getQuInsert()){
            Set<Integer> set = unreal.getDoneQuestionIdSet();
            List<Question> doneSet = questionService.getEnable(set);
            QuestionListVO vo = new QuestionListVO();
            vo.setEnable(true);
            int total = questionService.sizeQuestion(vo);
            int dones = doneSet.size();
            if(unreal.getDones() != dones || total != unreal.getQuTotal()){
                unreal.afterQuestionBankUpdate(total ,doneSet.stream().map(Question::getId).collect(Collectors.toList()));
                unrealMapper.updateExamUnreal(unreal);
            }
        }
    }

    @Override
    public PageResult<ExamUnreal> page(ExamUnrealListVO listVO) {
        int total = unrealMapper.size(listVO);
        PageResult<ExamUnreal> pageResult = new PageResult<>(listVO.getPageNo(), listVO.getPageSize(), total);
        if (total > 0) {
            List<ExamUnreal> list = unrealMapper.list(listVO);
            if(!list.isEmpty()) {
                QuestionBank bank = bankService.getBank();
                for (ExamUnreal unreal : list) {
                    belowQuestionBankVersion(unreal ,bank);
                }
            }
            pageResult.addAll(list);
        }
        return pageResult;
    }

    @Override
    public List<ExamUnrealQuestionData> getUnrealQuestionData(long uid) {
        List<Question> list = new ArrayList<>();
        QuestionListVO listVO = new QuestionListVO();
        listVO.setPageSize(100);
        listVO.setEnable(true);
        PageResult<Question> pageResult;
        do {
            pageResult = questionService.get(listVO);
            list.addAll(pageResult.getData());
            listVO.setPageNo(listVO.getPageNo() + 1);
        }while (listVO.getPageNo() < pageResult.getTotalPage());

        ExamUnreal tmp = getByUid(uid);
        if(tmp == null){
            tmp = ExamUnreal.buildDefault(uid ,pageResult.getTotal());
        }
        ExamUnreal unreal = tmp;
        List<ExamUnrealQuestionData> datas = list.stream().map(q -> {
            ExamUnrealQuestionData data = new ExamUnrealQuestionData();
            data.setDone(unreal.idDone(q.getId()));
            if(!data.isDone()){
                q.unloadAnswer();
            }
            data.setQuestion(q);
            data.setUserAnswer(unreal.getAnswer(q.getId()));
            data.setRight(q.answerResult(data.getUserAnswer()));

            return data;
        }).collect(Collectors.toList());

        return datas;
    }

    @Override
    public ExamUnreal getByUid(long uid) {
        ExamUnreal unreal = unrealMapper.getByUid(uid);

        QuestionBank bank = bankService.getBank();
        belowQuestionBankVersion(unreal ,bank);

        return unreal;
    }

    @Override
    @Transactional
    public ExamUnrealAnswer submitAnswer(long uid, int qid, String answer) {
        ExamUnreal unreal = getByUid(uid);
        boolean exist = true;
        if (unreal == null) {
            exist = false;
            QuestionListVO listVO = new QuestionListVO();
            listVO.setEnable(true);
            unreal = ExamUnreal.buildDefault(uid ,questionService.sizeQuestion(listVO));
        }
        Question question = questionService.get(qid);
        boolean answerResult = question.answerResult(answer);
        if (!unreal.idDone(qid)) {
            unreal.addAnswer(qid, answer, answerResult);

            if (exist) {
                unrealMapper.updateExamUnreal(unreal);
            } else {
                unrealMapper.addExamUnreal(unreal);
            }
        }
        ExamUnrealAnswer as = new ExamUnrealAnswer();
        as.setAnswer(question.getAnswer());
        as.setRight(answerResult);
        return as;
    }

    @Override
    public void add(ExamUnreal unreal) {
        unreal.verifyComplete();
        unreal.setDefault();
        if(unreal.getQuTotal() == null){
            QuestionListVO listVO = new QuestionListVO();
            listVO.setEnable(true);
            int total =questionService.sizeQuestion(listVO);
            unreal.setQuTotal(total);
        }
        unrealMapper.addExamUnreal(unreal);
    }

    @Override
    public void update(ExamUnreal unreal) {
        if (unreal.getId() == null) {
            throw new IllegalArgumentException("id cannot be null");
        }
        unrealMapper.updateExamUnreal(unreal);
    }
}
